﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
using CSharpHelpers.IOs;

namespace CSharpHelpers.Medias
{
    class VideoHelper
    {
        private const int WM_USER = 0x400;
        private const int WS_CHILD = 0x40000000;
        private const int WS_VISIBLE = 0x10000000;
        private const int WM_CAP_START = WM_USER;
        private const int WM_CAP_STOP = WM_CAP_START + 68;
        private const int WM_CAP_DRIVER_CONNECT = WM_CAP_START + 10;
        private const int WM_CAP_DRIVER_DISCONNECT = WM_CAP_START + 11;
        private const int WM_CAP_SAVEDIB = WM_CAP_START + 25;
        private const int WM_CAP_GRAB_FRAME = WM_CAP_START + 60;
        private const int WM_CAP_SEQUENCE = WM_CAP_START + 62;
        private const int WM_CAP_FILE_SET_CAPTURE_FILEA = WM_CAP_START + 20;
        private const int WM_CAP_SEQUENCE_NOFILE = WM_CAP_START + 63;
        private const int WM_CAP_SET_OVERLAY = WM_CAP_START + 51;
        private const int WM_CAP_SET_PREVIEW = WM_CAP_START + 50;
        private const int WM_CAP_SET_CALLBACK_VIDEOSTREAM = WM_CAP_START + 6;
        private const int WM_CAP_SET_CALLBACK_ERROR = WM_CAP_START + 2;
        private const int WM_CAP_SET_CALLBACK_STATUSA = WM_CAP_START + 3;
        private const int WM_CAP_SET_CALLBACK_FRAME = WM_CAP_START + 5;
        private const int WM_CAP_SET_SCALE = WM_CAP_START + 53;
        private const int WM_CAP_SET_PREVIEWRATE = WM_CAP_START + 52;
        private IntPtr hWndC;
        private bool bWorkStart = false;
        private IntPtr mControlPtr;
        private int mWidth;
        private int mHeight;
        private int mLeft;
        private int mTop;


        /**/

        ///   <summary> 
        ///   初始化显示图像 
        ///   </summary> 
        ///   <param   name= "handle "> 控件的句柄 </param> 
        ///   <param   name= "left "> 开始显示的左边距 </param> 
        ///   <param   name= "top "> 开始显示的上边距 </param> 
        ///   <param   name= "width "> 要显示的宽度 </param> 
        ///   <param   name= "height "> 要显示的长度 </param> 
        public VideoHelper(IntPtr handle, int left, int top, int width, int height)
        {
            mControlPtr = handle;
            mWidth = width;
            mHeight = height;
            mLeft = left;
            mTop = top;
        }

        [DllImport("avicap32.dll ")]
        private static extern IntPtr capCreateCaptureWindowA(byte[] lpszWindowName, int dwStyle, int x, int y,
            int nWidth, int nHeight, IntPtr hWndParent, int nID);

        [DllImport("avicap32.dll ")]
        private static extern int capGetVideoFormat(IntPtr hWnd, IntPtr psVideoFormat, int wSize);

        // 
        //这里特别注意，因为WinAPI中的long为32位，而C#中的long为64wei，所以需要将lParam该为int 
        // 
        [DllImport("User32.dll ")]
        private static extern bool SendMessage(IntPtr hWnd, int wMsg, int wParam, int lParam);

        /**/

        ///   <summary> 
        ///   开始显示图像 
        ///   </summary> 
        public void Start()
        {
            if (bWorkStart)
                return;
            bWorkStart = true;
            byte[] lpszName = new byte[100];

            hWndC = capCreateCaptureWindowA(lpszName, WS_CHILD | WS_VISIBLE, mLeft, mTop, mWidth, mHeight, mControlPtr,
                0);
            if (hWndC.ToInt32() != 0)
            {
                SendMessage(hWndC, WM_CAP_SET_CALLBACK_VIDEOSTREAM, 0, 0);
                SendMessage(hWndC, WM_CAP_SET_CALLBACK_ERROR, 0, 0);
                SendMessage(hWndC, WM_CAP_SET_CALLBACK_STATUSA, 0, 0);
                SendMessage(hWndC, WM_CAP_DRIVER_CONNECT, 0, 0);
                SendMessage(hWndC, WM_CAP_SET_SCALE, 1, 0);
                SendMessage(hWndC, WM_CAP_SET_PREVIEWRATE, 66, 0);
                SendMessage(hWndC, WM_CAP_SET_OVERLAY, 1, 0);
                SendMessage(hWndC, WM_CAP_SET_PREVIEW, 1, 0);
                //Global.log.Write( "SendMessage "); 
            }
            return;

        }

        /**/

        ///   <summary> 
        ///   停止显示 
        ///   </summary> 
        public void Stop()
        {
            SendMessage(hWndC, WM_CAP_DRIVER_DISCONNECT, 0, 0);
            bWorkStart = false;
        }

        /**/

        #region 录像

        //要保存avi文件的路径
        public void Kinescope(string path)
        {

            IntPtr hBmp = Marshal.StringToHGlobalAnsi(path);

            SendMessage(hWndC, WM_CAP_FILE_SET_CAPTURE_FILEA, 0, hBmp.ToInt32());

            SendMessage(hWndC, WM_CAP_SEQUENCE, 0, 0);

        }

        /// <summary>
        /// 停止录像
        /// </summary>
        public void StopKinescope()
        {
            SendMessage(hWndC, WM_CAP_STOP, 0, 0);
        }

        #endregion

        ///   <summary> 
        ///   抓图 
        ///   </summary> 
        ///   <param   name= "path "> 要保存bmp文件的路径 </param> 
        public void GrabImage(string path)
        {
            IntPtr hBmp = Marshal.StringToHGlobalAnsi(path);
            SendMessage(hWndC, WM_CAP_SAVEDIB, 0, hBmp.ToInt32());

        }

        public byte[] Cap(string path, int x, int y)
        {
            var arr = new byte[] { };
            try
            {
                Image tmpImage = GetCutScreenImage(x, y, 400, 480);
                arr = ImageToByteArray(tmpImage);

                //Clipboard.Clear();
                //SendMessage(hWndC, 0x41e, 0, 0);
                //var obj1 = Clipboard.GetDataObject();
                //if (obj1 != null && obj1.GetDataPresent(typeof(Bitmap)))
                //{
                //    Bitmap bmap = (Bitmap)obj1.GetData(typeof(Bitmap));
                //    bmap.Save(path, ImageFormat.Jpeg);

                //    Image tmpImage = Images("~atm_temp.jpg");
                //    arr = ImageToByteArray(tmpImage);
                //}
            }
            catch (Exception e)
            {
                SystemLog.Error("拍照發生異常: " + e);
            }


            return arr;
        }

        public byte[] ImageToByteArray(Image img)
        {
            if (img != null)
            {
                //将Image转换成流数据，并保存为byte[] 
                MemoryStream mstream = new MemoryStream();
                img.Save(mstream, ImageFormat.Jpeg);
                Byte[] byData = new Byte[mstream.Length];
                mstream.Position = 0;
                mstream.Read(byData, 0, byData.Length);
                mstream.Close();
                mstream.Dispose();
                img.Dispose();

                return byData;
            }

            return new byte[0];
        }

        public Image Images(string imagesName, string folderName = "")
        {
            try
            {
                string imageUrl = ImagesUrl(imagesName);
                if (!File.Exists(imageUrl))
                {
                    return null;
                }

                FileStream fs = new FileStream(imageUrl, FileMode.Open, FileAccess.Read);
                lock (fs)
                {
                    //把文件读取到字节数组   
                    byte[] data = new byte[fs.Length];
                    fs.Read(data, 0, data.Length);
                    fs.Close();
                    //实例化一个内存流--->把从文件流中读取的内容[字节数组]放到内存流中去  
                    MemoryStream ms = new MemoryStream(data);
                    //设置图片框 pictureBox1中的图片
                    return Image.FromStream(ms);
                }
            }
            catch (Exception e)
            {
                SystemLog.Error("Reader image:" + e);
                throw;
            }
        }

        public string ImagesUrl(string imagesName)
        {
            string imageUrl = Application.StartupPath + String.Format("\\{0}", imagesName);
            return imageUrl;
        }

        /// <summary>
        /// 生成缩略图重载方法1，返回缩略图的Image对象
        /// </summary>
        /// <param name="resourceImage">图片资源</param>
        /// <param name="width">缩略图的宽度</param>
        /// <param name="height">缩略图的高度</param>
        /// <returns>缩略图的Image对象</returns>
        public Image GetReducedImage(Image resourceImage, int width, int height)
        {
            //用指定的大小和格式初始化Bitmap类的新实例
            Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb);

            //从指定的Image对象创建新Graphics对象
            Graphics graphics = Graphics.FromImage(bitmap);

            //清除整个绘图面并以透明背景色填充
            graphics.Clear(Color.Transparent);

            //在指定位置并且按指定大小绘制原图片对象
            graphics.DrawImage(resourceImage, new Rectangle(0, 0, width, height));

            graphics.Dispose();

            return bitmap;
        }

        /// <summary>
        /// 根据指定大小截取图象
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <returns></returns>
        private Image GetCutScreenImage(int x, int y, int width, int height)
        {
            //创建图象，保存将来截取的图象
            Bitmap image = new Bitmap(width, height);
            Graphics imgGraphics = Graphics.FromImage(image);
            //设置截屏区域
            imgGraphics.CopyFromScreen(x, y, 0, 0, new Size(width, height));

            //保存
            return image;
        }

        #region 数据转换

        /// <summary>
        /// 16进制字符串 转成 byte[]，每连个 字符代表一个16进制值 转为一个 byte
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public static byte[] HexStringByteArrayToByteArray(byte[] data)
        {
            var str = Encoding.ASCII.GetString(data);
            var listByte = new List<byte>();
            for (int i = 0; i < (str.Length / 2); i++)
            {
                var hex = Convert.ToInt32(str.Substring(i * 2, 2), 16);
                listByte.Add((byte)hex);
            }

            return listByte.ToArray();
        }

        /// <summary>
        /// byte[]  每一个byte 转为两个字符串的16进制值
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public static byte[] ByteArrayToHexStringByteArray(byte[] data)
        {
            var sb = new StringBuilder();
            foreach (byte b in data)
            {
                string hexStr = Convert.ToString(b, 16);
                if (hexStr.Length < 2)
                {
                    hexStr = "0" + hexStr;
                }
                sb.Append(hexStr.ToUpper());
            }

            var byteArray = Encoding.ASCII.GetBytes(sb.ToString());
            return byteArray;

        }

        #endregion
    }
}
